local m = {}

m.PrintTable = require("SharedLibs.Utils.PrintTable");

--- 将数组转换为一个Table，Table的key是数组元素的key字段
function m.ArrayToTable(arr, key)
	assert(arr);	
	key = key or "key";
	
	local map = {};
	for _, item in ipairs(arr) do
		local itemKey = item[key];
		---if itemKey == nil then warn(g.PrintTable(prop)); end		
		assert(itemKey, "'"..key.."'".." not found in item: "..m.PrintTable(item));
		assert(not map[itemKey], "Duplicate "..itemKey) --- 不允许重复！
		map[itemKey] = item; 
	end
	return map;
end

--- 将一个 Table 转换成 Array
--- table的key会传递给keyFunc(), 上层可以对key做一些逻辑, 例如可以将所有key都作为item 的 type
function m.ToArray(tbl, keyFunc)
	local arr = {};
	if keyFunc then
		for key, v in pairs(tbl) do
			keyFunc(key, v);
			table.insert(arr, v);
		end
	else
		for _, v in pairs(tbl) do
			table.insert(arr, v);
		end
	end
	return arr;
end

--- 对Table的所有元素用f映射为新元素。
--- (f is a map function)
function m.MapTable(tbl, f)
    local t = {}
    for k,v in pairs(tbl) do
        t[k] = f(v)
    end
    return t
end

--- f is a map function
function m.ForEach(tbl, f)
	for k,v in pairs(tbl) do
		f(v, k);
	end
	return tbl;
end

function m.ShallowCopy(tb)
	local copy = {}
	for k, v in pairs(tb) do
		copy[k] = v
	end
	return copy;
end

--- Merge t2 into t1
function m.MergeTable(t1, t2)
	for k,v in pairs(t2) do
		t1[k] = v;
	end
	return t1;
end

--- Return table item cout
function m.GetTableSize(t)
	local size = 0;
	for k,v in pairs(t) do
		size = size + 1;
	end
	return size;
end

--- Test array equality. The array item must be simple type.
--- Note: if a1's first value is nil, it will always return true (incorrect)
function m.ArrayEqual(a1, a2)
	if #a1 ~= #a2 then return false end;
	for i, v in ipairs(a1) do
		if a2[i] ~= v then return false end;
	end
	return true;
end

function m.ArrayContains(array, val)
	for index, value in ipairs(array) do
		if value == val then
			return true
		end
	end

	return false
end

function m.TableContains(table, val)
	for key, value in pairs(table) do
		if value == val then
			return true	
		end
	end
	return false
end

function m.MergeArrays(array1, array2)
	local newArr = {}
	for i=1,#array1 do
	  table.insert(newArr, array1[i])
	end
	for i=1,#array2 do
	  table.insert(newArr, array2[i])
	end
	return newArr
end

function m.ClearArray(array)
	for index, value in ipairs(array) do
		array[index] = nil;
	end

	return false
end

--- Shallow copy array
function m.CopyArray(array)
	local clone = {table.unpack(array)};
	return clone;
end

--- support table type only
local function _deepcopy(o, seen)
	seen = seen or {}
	if o == nil then return nil end
	if seen[o] then return seen[o] end


	local no = {}
	seen[o] = no
	setmetatable(no, _deepcopy(getmetatable(o), seen))

	for k, v in next, o, nil do
		k = (type(k) == 'table') and _deepcopy(k, seen) or k
		v = (type(v) == 'table') and _deepcopy(v, seen) or v
		no[k] = v
	end
	return no
end

function m.DeepCopy(o, seen)
	if type(o) == 'table' then
		return _deepcopy(o, seen);
	else -- number, string, boolean, etc
		return o;
	end
end 

return m;
